xen_pfn_t *p2m; /* A table mapping each PFN to its new MFN. */
xen_pfn_t *p2m_batch; /* A table of P2M mappings in the current region. */
int completed; /* Set when a consistent image is available */
+ int last_checkpoint; /* Set when we should commit to the current checkpoint when it completes. */
struct domain_info_context dinfo;
};
// DPRINTF("console pfn location: %llx\n", buf->console_pfn);
return pagebuf_get_one(xch, ctx, buf, fd, dom);
+ case XC_SAVE_ID_LAST_CHECKPOINT:
+ ctx->last_checkpoint = 1;
+ // DPRINTF("last checkpoint indication received");
+ return pagebuf_get_one(xch, ctx, buf, fd, dom);
+
default:
if ( (count > MAX_BATCH_SIZE) || (count < 0) ) {
ERROR("Max batch size exceeded (%d). Giving up.", count);
goto out;
}
ctx->completed = 1;
- /* shift into nonblocking mode for the remainder */
- if ( (flags = fcntl(io_fd, F_GETFL,0)) < 0 )
- flags = 0;
- fcntl(io_fd, F_SETFL, flags | O_NONBLOCK);
+
+ /*
+ * If more checkpoints are expected then shift into
+ * nonblocking mode for the remainder.
+ */
+ if ( !ctx->last_checkpoint )
+ {
+ if ( (flags = fcntl(io_fd, F_GETFL,0)) < 0 )
+ flags = 0;
+ fcntl(io_fd, F_SETFL, flags | O_NONBLOCK);
+ }
+ }
+
+ if ( ctx->last_checkpoint )
+ {
+ // DPRINTF("Last checkpoint, finishing\n");
+ goto finish;
}
// DPRINTF("Buffered checkpoint\n");
}
}
+ if ( !callbacks->checkpoint )
+ {
+ /*
+ * If this is not a checkpointed save then this must be the first and
+ * last checkpoint.
+ */
+ i = XC_SAVE_ID_LAST_CHECKPOINT;
+ if ( wrexact(io_fd, &i, sizeof(int)) )
+ {
+ PERROR("Error when writing last checkpoint chunk");
+ goto out;
+ }
+ }
+
/* Zero terminate */
i = 0;
if ( wrexact(io_fd, &i, sizeof(int)) )